#include <crt_util.h>
#include "compat_event_util.h"

#if (TARGET_OS == OS_WIN)
#include "compat_event_iocp.h"
#include "compat_event_win32.h"
#elif (TARGET_OS == OS_POSIX)
#include "compat_event_epoll.h"
#include "compat_event_posix.h"
#elif (TARGET_OS == OS_MACH)
#include "compat_event_kqueue.h"
#include "compat_event_mach.h"
#elif (TARGET_OS == OS_UNIX)
#include "compat_event_kqueue.h"
#include "compat_event_mach.h"
#endif

static int oper_msec_less_than(const _heap_node_t* node_a, const _heap_node_t* node_b)
{
    const struct evoper_s* a;
    const struct evoper_s* b;

    a = _container_of(node_a, struct evoper_s, node);

    b = _container_of(node_b, struct evoper_s, node);

    if (a->msec < b->msec)
        return 1;

    if (b->msec < a->msec)
        return 0;

    return 0;
}
int evloop_nodes_addtime(evloop_nodes_t* nodes, evoper_t* add)
{
    rc_error(nodes != NULL, S_ERROR);
    heap_insert((_heap_t*)&nodes->heap, (_heap_node_t*)&add->node, oper_msec_less_than);
    return S_SUCCESS;
}
int evloop_nodes_deltime(evloop_nodes_t* nodes, evoper_t* del)
{
    rc_error(nodes != NULL, S_ERROR);
    heap_remove((_heap_t*)&nodes->heap, (_heap_node_t*)&del->node, oper_msec_less_than);
    return S_SUCCESS;
}

int evloop_nodes_gettime(evloop_nodes_t* nodes, evoper_t** get)
{
    rc_error(nodes->heap.count != 0, S_NOFOUND);
    evoper_t* oper = NULL;
    oper = _container_of(heap_root(&nodes->heap), struct evoper_s, node);
    rc_error(oper != NULL, S_NOFOUND);
    *get = oper;
    return S_FOUND;
}
int evloop_nodes_init(evloop_nodes_t* nodes)
{
    rc_error(nodes != NULL, S_ERROR);
    heap_init(&nodes->heap);
    return S_SUCCESS;
}
int evloop_nodes_uninit(evloop_nodes_t* nodes)
{
    rc_error(nodes != NULL, S_ERROR);
    return S_SUCCESS;
}
int evloop_nodes_count(evloop_nodes_t* nodes, uint64_t* count)
{
    rc_error(nodes != NULL, S_ERROR);
    *count = nodes->heap.count;
    return S_SUCCESS;
}
int evloop_queue_init(evloop_queue_t* queue)
{
    rc_error(queue != NULL, S_ERROR);
    _queue_init(queue);
    return S_SUCCESS;
}
int evloop_queue_uninit(evloop_queue_t* queue)
{
    rc_error(queue != NULL, S_ERROR);

    return S_SUCCESS;
}
int evloop_add_ev(evloop_queue_t* queue, evoper_queue* ev)
{
    rc_error(queue != NULL, S_ERROR);
    _queue_insert_tail(queue, ev);
    return S_SUCCESS;
}
int evloop_del_ev(evloop_queue_t* queue, evoper_queue* ev)
{
    rc_error(queue != NULL, S_ERROR);
    _queue_remove(ev);
    return S_SUCCESS;
}
int evloop_clock_init(evloop_clock_t* clock)
{
    rc_error(clock != NULL, S_ERROR);
    _clock_init(&clock->clock);
    return S_SUCCESS;
}
int evloop_clock_uninit(evloop_clock_t* clock)
{
    rc_error(clock != NULL, S_ERROR);
    return S_SUCCESS;
}
int evloop_clock_update(evloop_clock_t* clock)
{
    rc_error(clock != NULL, S_ERROR);
    struct timeval tv;
    get_clock(&clock->clock, &tv);
    clock_adjust(&clock->clock, &tv);
    clock->msec = tv_to_msec(&clock->clock.monotonic_clock);
    return S_SUCCESS;
}
int evloop_clock_setmsec(evloop_clock_t* clock, crt_msec msec)
{
    rc_error(clock != NULL, S_ERROR);
    clock->msec = msec;
    return S_SUCCESS;
}
int evloop_clock_getmsec(evloop_clock_t* clock, crt_msec* msec)
{
    rc_error(clock != NULL, S_ERROR);
    *msec = clock->msec;
    return S_SUCCESS;
}
int evloop_bind_evbase(evloop_t* loop, void* evbase)
{
    rc_error(loop != NULL, S_ERROR);
    loop->evbase = evbase;
    return S_SUCCESS;
}
void* evloop_evbase(evloop_t* loop)
{
    rc_error(loop != NULL, NULL);
    return loop->evbase;
}
void* evloop_sysop(evloop_t* loop)
{
    rc_error(loop != NULL, NULL);
    return loop->sysop;
}
void* evoper_evbase(evoper_t* oper)
{
    rc_error(oper != NULL, NULL);
    evloop_t* loop = oper->loop;
    rc_error(loop != NULL, NULL);
    return evloop_evbase(loop);
}
void* evoper_private(evoper_t* oper)
{
    rc_error(oper != NULL, NULL);
    return oper->private;
}
int evoper_bind_private(evoper_t* oper, void* obj)
{
    rc_error(oper != NULL, S_ERROR);
    oper->private = obj;
    return S_SUCCESS;
}
int evoper_op_init(evoper_t* oper)
{
    rc_error(oper != NULL, S_ERROR);

    oper->read = op_ev_read;
    oper->write = op_ev_write;
    oper->accept = op_ev_accept;
    oper->open = op_ev_open;
    oper->conn = op_ev_connect;
    oper->close = op_ev_close;

    oper->oneshot = ev_off;
    oper->eof = ev_off;
    oper->post = ev_off;
    oper->err = ev_off;
    oper->vnode = ev_off;
    oper->pending_eof = ev_off;

    return S_SUCCESS;
}
int evoper_connect_op(evoper_t* oper, evevent op)
{
    rc_error(oper != NULL, S_ERROR);
    oper->conn = op;
    return S_SUCCESS;
}
int evoper_connected(evoper_t* oper)
{
    rc_error(oper != NULL, S_ERROR);
    return oper->conn == op_ev_connected ? S_SUCCESS : S_ERROR;
}
int evoper_accept_op(evoper_t* oper, evevent op)
{
    rc_error(oper != NULL, S_ERROR);
    oper->accept = op;
    return S_SUCCESS;
}
int evoper_listen_size(evoper_t* oper, evoper_ls ls)
{
    rc_error(oper != NULL, S_ERROR);
    oper->ls = ls;
    return S_SUCCESS;
}
int evoper_read_op(evoper_t* oper, evevent op)
{
    rc_error(oper != NULL, S_ERROR);
    oper->read = op;
    return S_SUCCESS;
}
int evoper_reading(evoper_t* oper)
{
    rc_error(oper != NULL, S_ERROR);
    return oper->read == op_ev_reading ? S_SUCCESS : S_ERROR;
}
int evoper_write_op(evoper_t* oper, evevent op)
{
    rc_error(oper != NULL, S_ERROR);
    oper->write = op;
    return S_SUCCESS;
}
int evoper_writeing(evoper_t* oper)
{
    rc_error(oper != NULL, S_ERROR);
    return oper->write == op_ev_writeing ? S_SUCCESS : S_ERROR;
}
int evoper_closeing(evoper_t* oper)
{
    rc_error(oper != NULL, S_ERROR);

    if (oper->close >= op_ev_closeing && oper->close <= op_ev_closed)
        return S_SUCCESS;

    return S_ERROR;
}
int evoper_close_op(evoper_t* oper, evevent op)
{
    rc_error(oper != NULL, S_ERROR);
    oper->close = op;
    return S_SUCCESS;
}
int evoper_post_op(evoper_t* oper, evevent op)
{
    rc_error(oper != NULL, S_ERROR);
    oper->post = op;
    return S_SUCCESS;
}
int evoper_eofing(evoper_t* oper)
{
    rc_error(oper != NULL, S_ERROR);
    return oper->eof == ev_on ? S_SUCCESS : S_ERROR;
}
int evoper_eof_op(evoper_t* oper, evevent op)
{
    rc_error(oper != NULL, S_ERROR);
    oper->eof = op;
    return S_SUCCESS;
}
int evoper_erring(evoper_t* oper)
{
    rc_error(oper != NULL, S_ERROR);
    return oper->err == ev_on ? S_SUCCESS : S_ERROR;
}
int evoper_err_op(evoper_t* oper, evevent op)
{
    rc_error(oper != NULL, S_ERROR);
    oper->err = op;
    return S_SUCCESS;
}
int evoper_assign_sock(evoper_t* oper, _sock_t sock)
{
    int rc = S_ERROR;
    rc = set_blocking(sock, 1);
    rc_error(rc == S_SUCCESS, S_ERROR);

    evoper_bind_sock(oper, sock);
    rc_error(rc == S_SUCCESS, S_ERROR);

    evoper_bind_type(oper, ev_sock);
    rc_error(rc == S_SUCCESS, S_ERROR);

    return S_SUCCESS;
}
int evoper_sock_connect(evoper_t* oper, const evaddr_t* addr)
{
    rc_error(oper != NULL, S_ERROR);
    rc_error(addr != NULL, S_ERROR);
    return _asynconnect_sockv4(oper->sock, addr->ptr, addr->len, addr->port);
}
int evoper_sock_connected(evoper_t* oper)
{
    // win iocp https://learn.microsoft.com/zh-cn/windows/win32/api/Mswsock/nc-mswsock-lpfn_connectex

    int rc = S_ERROR;
    rc_error(oper != NULL, S_ERROR);
#if (TARGET_OS == OS_WIN)
    rc = win32_sock_connectexed(oper);
#else
    rc = _connected_socket(oper->sock);
#endif
    return rc;
}
int complete_sock_accept(evloop_t* loop, int err, crterr code, evoper_t* oper, evoper_t* oper_t, ev_op func)
{
    evoper_ls l = 0;
    rc_error(oper != NULL, S_ERROR);
    rc_error(loop != NULL, S_ERROR);
    rc_error(func != NULL, S_ERROR);

#if (TARGET_OS == OS_WIN)
    // oper->bind = 1;
    evoper_connect_op(oper_t, op_ev_connected);
    func(err == 0 ? S_SUCCESS : S_ERROR, err, oper, oper_t, op_ev_accept);
#else
    evoper_ls ls = oper->ls;

    for (l = 0; l < ls; l++) {
        struct sockaddr_in cliaddr;
        socklen_t clilen = sizeof(struct sockaddr_in);
        int accept_sock = -1;

        accept_sock = accept(oper->sock, (struct sockaddr*)&cliaddr, &clilen);
        rc_error_break(accept_sock != -1);

        evoper_t* oper_s = (evoper_t*)loop->mm_malloc(loop, 1, sizeof(evoper_t));
        rc_error_break(oper_s != NULL);

        evoper_assign_sock(oper_s, accept_sock);

        evloop_alloc_evoper(loop, oper_s);

        // oper_s connected
        evoper_connect_op(oper_s, op_ev_connected);

        func(S_SUCCESS, err, oper, oper_s, op_ev_accept);
    }
#endif
    return S_SUCCESS;
}
int complete_sock_connect(evloop_t* loop, int err, crterr code, evoper_t* oper, ev_op func)
{
    rc_error(oper != NULL, S_ERROR);
    rc_error(loop != NULL, S_ERROR);
    rc_error(func != NULL, S_ERROR);

    evevent res = evoper_sock_connected(oper) == S_SUCCESS ? op_ev_connected : op_ev_connectfailed;
    evoper_connect_op(oper, res);

    func(err, code, oper, NULL, op_ev_connect);

    return S_SUCCESS;
}
int complete_sock_close(evloop_t* loop, int err, crterr code, evoper_t* oper, ev_op func)
{
    rc_error(oper != NULL, S_ERROR);
    rc_error(loop != NULL, S_ERROR);
    rc_error(func != NULL, S_ERROR);
    func(err, code, oper, NULL, op_ev_close);
    evoper_close_op(oper, op_ev_closed);
    return S_SUCCESS;
}
int complete_sock_read(evloop_t* loop, int err, crterr code, evoper_t* oper, ev_op func)
{
    rc_error(oper != NULL, S_ERROR);
    rc_error(loop != NULL, S_ERROR);
    rc_error(func != NULL, S_ERROR);

    if (evoper_reading(oper) == S_SUCCESS) {
#if (TARGET_OS == OS_WIN)
        func(err, code, oper, NULL, op_ev_read);
#elif (TARGET_OS == OS_POSIX)
		evoper_tcpsock_recv(oper, err, code, func);
#elif (TARGET_OS == OS_MACH || TARGET_OS == OS_UNIX)
		evoper_tcpsock_recv(oper, err, code, func);
#else

#endif
    }
    return S_SUCCESS;
}
int complete_sock_write(evloop_t* loop, int err, crterr code, evoper_t* oper, ev_op func)
{
    rc_error(oper != NULL, S_ERROR);
    rc_error(loop != NULL, S_ERROR);
    rc_error(func != NULL, S_ERROR);

    if (evoper_writeing(oper) == S_SUCCESS) {
        func(err, code, oper, NULL, op_ev_write);
    }
    return S_SUCCESS;
}
int evbuf_init(evbuf_t* buf)
{
    rc_error(buf != NULL, S_ERROR);
    _mutex_init(&buf->lock);
    return S_SUCCESS;
}
int evbuf_uninit(evbuf_t* buf)
{
    rc_error(buf != NULL, S_ERROR);
    _mutex_unlock(&buf->lock);
    return S_SUCCESS;
}
int evbuf_is_eof(evbuf_t* buf)
{
    rc_error(buf != NULL, S_ERROR);
    return buf->len == buf->off ? S_SUCCESS : S_ERROR;
}
int evbuf_bind(evbuf_t* buf, buf_ptr ptr, buf_len len, buf_len off)
{
    rc_error(buf != NULL, S_ERROR);
    rc_error(ptr != NULL, S_ERROR);
    rc_error(len != 0, S_ERROR);

    buf->ptr = ptr;
    buf->len = len;
    buf->off = off;

    return S_SUCCESS;
}
int evbuf_get_buf(evbuf_t* buf, buf_ptr* ptr)
{
    rc_error(buf != NULL, S_ERROR);
    *ptr = buf->ptr;
    return S_SUCCESS;
}
int evbuf_get_len(evbuf_t* buf, buf_len* len)
{
    rc_error(buf != NULL, S_ERROR);
    *len = buf->len;
    return S_SUCCESS;
}
int evbuf_get_off(evbuf_t* buf, buf_len* off)
{
    rc_error(buf != NULL, S_ERROR);
    *off = buf->off;
    return S_SUCCESS;
}
int evbuf_set_off(evbuf_t* buf, buf_len off)
{
    rc_error(buf != NULL, S_ERROR);
    buf->off = off;
    return S_SUCCESS;
}
int evbuf_op_off(evbuf_t* buf, buf_len off)
{
    rc_error(buf != NULL, S_ERROR);

    _mutex_lock(&buf->lock);
    buf->off += off;
    _mutex_unlock(&buf->lock);

    return S_SUCCESS;
}
int is_evbuf_compelete(evbuf_t* buf)
{
    rc_error(buf != NULL, S_ERROR);
    return buf->off == buf->len ? S_SUCCESS : S_ERROR;
}
int evoper_set_rbyte(evoper_t* oper, buf_len byte)
{
    rc_error(oper != NULL, S_ERROR);
    return oper->rbuf.byte = byte;
}
int evoper_set_wbyte(evoper_t* oper, buf_len byte)
{
    rc_error(oper != NULL, S_ERROR);
    return oper->wbuf.byte = byte;
}
int evs_init(evs_t* on)
{
    rc_error(on != NULL, S_ERROR);
    _atomic_init(&on->v);
    return S_SUCCESS;
}
int evs_uninit(evs_t* on)
{
    rc_error(on != NULL, S_ERROR);
    _atomic_uninit(&on->v);
    return S_SUCCESS;
}
int evs_on(evs_t* on)
{
    rc_error(on != NULL, S_ERROR);
    _atomic_add(&on->v);
    return S_SUCCESS;
}
int evs_off(evs_t* on)
{
    rc_error(on != NULL, S_ERROR);
    _atomic_init(&on->v);
    return S_SUCCESS;
}
int is_evs_on(evs_t* on)
{
    rc_error(on != NULL, S_ERROR);
    if (_atomic_cmp(1, &on->v)) {
        return S_SUCCESS;
    }
    return S_ERROR;
}

#if (TARGET_OS != OS_WIN)

int evoper_tcpsock_send(evoper_t* oper, int err, crterr code, ev_op func)
{
	int rc = S_SUCCESS;
	rc_error(oper != NULL, rc);

	for (;;) {
		
		ssize_t n = 0;
		int error = 0;
		buf_ptr ptr = NULL;
		buf_len len = 0;
		
		rc = evbuf_get_buf(&oper->wbuf, &ptr);
		rc_error(rc != S_ERROR, S_ERROR);

		rc = evbuf_get_len(&oper->wbuf, &len);
		rc_error(rc != S_ERROR, S_ERROR);


		/*
		if use set_sendbuflen(oper->sock, 1);
		order error
		*/

		n = write(oper->fd, ptr, len);

		error = (n == -1) ? errno : 0;

		if (n > 0) {
			evoper_set_wbyte(oper, n);
			evbuf_op_off(&oper->wbuf, n);
			func(err, code, oper, oper, op_ev_write);
		}

		if (evoper_writeing(oper) == S_ERROR)
			break;

				
		if (error != 0) {
			if(error == EAGAIN) {
				return S_PENDING;
			} else if (error == EINTR) {
				continue;
			} else {
				return S_ERROR;
			}
		}
	}
	return rc;
}

int evoper_tcpsock_recv(evoper_t* oper, int err, crterr code, ev_op func)
{
	int rc = S_SUCCESS;
	rc_error(oper != NULL, rc);
 

	for (;;) {
		
		ssize_t n = 0;
		int error = 0;
		buf_ptr ptr = NULL;
		buf_len len = 0;

		rc = evbuf_get_buf(&oper->rbuf, &ptr);
		rc_error(rc != S_ERROR, S_ERROR);

		rc = evbuf_get_len(&oper->rbuf, &len);
		rc_error(rc != S_ERROR, S_ERROR);

		n = read(oper->fd, ptr, len);
		
		error = (n == -1) ? errno : 0;
		
		if (n > 0) {
			evoper_set_rbyte(oper, n);
			evbuf_op_off(&oper->rbuf, n);
			func(err, code, oper, NULL, op_ev_read);
		}
		
		if (evoper_reading(oper) == S_ERROR)
			break;
			
		if (error != 0) {
			if(error == EAGAIN) {
				return S_PENDING;
			} else if (error == EINTR) {
				continue;
			} else {
				return S_ERROR;
			}
		}
	
	}
	return rc;
}
#endif



